const APPID = 'c15ab7c9'
const API_SECRET = 'MWM2MzM3OGM1YzU2ZTcwNTBiZDg1YjU4'
const API_KEY = 'd03547e861eef0a29696f64563fc628b'
let textinfo = "undefined"
import urlUtil from "../utils/urlUtil"
import audio from '@ohos.multimedia.audio'
import fileio from '@ohos.fileio'
import webSocket from '@ohos.net.webSocket'
import { getP, GlobalContext, setP } from '../utils/GlobalContext'
import AccessibilityUtils from "../AccessibilityExtAbility/AccessibilityUtils"
import { monitor } from "../utils/fileUtils"
import Logger from '../utils/Logger'
import { promptAction } from '@kit.ArkUI'
import { sleep } from '../utils/DateTimeUtil';

let TAG = "_:_[VR]"

export interface Bridge {
  sourceValue: () => string;
  destValue: () => string;
  destValueAdd: (destvalue: string) => void;
  clearDestValue: () => void;
}

export default class VoiceRecogManager {
  autoRestart = false
  recordPath = ""
  displayStr = ""
  mainUrl =
    "wss://ws-api.xfyun.cn/v2/iat?authorization=YXBpX2tleT0iZDAzNTQ3ZTg2MWVlZjBhMjk2OTZmNjQ1NjNmYzYyOGIiLCBhbGdvcml0aG09ImhtYWMtc2hhMjU2IiwgaGVhZGVycz0iaG9zdCBkYXRlIHJlcXVlc3QtbGluZSIsIHNpZ25hdHVyZT0ibzVUeTBaTDI1SC9pekdKcEFNRVoveVJsWmpoY1hDbWMvM2UzTU1mejRnUT0i&date=Wed%2C+01+Jan+2025+01%3A47%3A35+GMT&host=ws-api.xfyun.cn"
  ws = null;
  capturer: audio.AudioCapturer = null
  arrayBufGlobal = null
  audioData = []
  dataArr = []
  sendReadMidStop = 0
  cntRead = 0
  lastRead = 0
  deltaRead = 200
  cntSend = 0
  lastSend = 0
  deltaSend = 200
  fd = 0
  bufSize = 12800
  audioStreamInfo: audio.AudioStreamInfo = {
    samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000,
    channels: audio.AudioChannel.CHANNEL_1,
    sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
    encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW
  }
  audioCapturerInfo: audio.AudioCapturerInfo = {
    source: audio.SourceType.SOURCE_TYPE_MIC,
    capturerFlags: 0
  }
  audioCapturerOptions: audio.AudioCapturerOptions = {
    streamInfo: this.audioStreamInfo,
    capturerInfo: this.audioCapturerInfo
  }

  constructor(recordPath, autoRestart) {
    this.autoRestart = autoRestart
    this.recordPath = recordPath
    console.log("_:_inside oninit")
    audio.createAudioCapturer(this.audioCapturerOptions).then((data) => {
      this.capturer = data;
      console.log(TAG, this.sendReadMidStop, "constructor,capturer is " + this.capturer)
    })
  }

  static runBridgeForever(bridge: Bridge) {
    let TAG = "_:_[bridge]"
    let clearId = setInterval(() => {
      try {
        let nowvalue = ""
        nowvalue = bridge.sourceValue()
        if (nowvalue != "") {
          bridge.destValueAdd(nowvalue)
          bridge.clearDestValue()
          console.log(TAG, bridge.destValue())
        }
        // await  sleep(1000)
      } catch (e) {
        console.error(TAG, JSON.stringify(e))
      }
    }, 1000)
    return clearId
  }

  async readOneFrame() {
    let TAG = "_:_readOneFrame"
    try {
      let arrayBuffer = await this.capturer.read(this.bufSize, true)
      let realBuf = new Int8Array(arrayBuffer)
      for (let i = 0; i < realBuf.length; i++) {
        this.audioData.push(realBuf[i])
      }
      console.log(TAG, this.sendReadMidStop, "read ArrayBuffer[" + (this.cntRead++) + "]:", "audioData",
        this.audioData.length - this.bufSize,
        "->", this.audioData.length)
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async readFrameReculsive() {
    let TAG = "_:_readFrameRecul"
    try {
      if (this.sendReadMidStop == 2) {
        return
      }
      await this.readOneFrame()
      return this.readFrameReculsive()
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async recordStart() {

    this.sendReadMidStop = 0
    this.cntRead = 0
    this.cntSend = 0
    let TAG = "_:_[recordStart]"
    try {
      await this.connectWS()
      console.log(TAG, this.sendReadMidStop, "websocket connected", "capturer state", this.capturer.state)
      if (this.capturer.state != 2) {
        await this.capturer.start()
      }
      console.log(TAG, this.sendReadMidStop, "capturer started")
      await this.readOneFrame()
      console.log(TAG, this.sendReadMidStop, "read one frame finish")
      await this.sendStartFrame()
      console.log(TAG, this.sendReadMidStop, "start frame sent")
      this.readFrameReculsive()
      this.sendMidReculsive()
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async sendMidReculsive() {
    let TAG = "_:_[sendMidReculsive]"
    try {
      if (this.sendReadMidStop == 2) {
        return
      }
      if (this.audioData.length > 0) {
        await this.sendMidFrame()
      } else {
        await  sleep(100)
      }
      return this.sendMidReculsive()
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async recordStop() {
    let TAG = "recordStop"
    try {
      this.sendReadMidStop = 1
      console.log(TAG, this.sendReadMidStop, "recordStoped.forceStop")
      await monitor({
        get: () => {
          return this.sendReadMidStop == 2
        }, set: (val) => {
        }, cond: true
      })
      console.log(TAG, this.sendReadMidStop, "recordStoped step2")
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async connectWS() {
    let TAG = "connectWS"
    try {
      let url = this.getWebSocketUrl()
      if (this.ws != null) {
        this.ws = null
      }
      this.ws = webSocket.createWebSocket();
      this.ws.on('message', async (err, value) => {
        console.log(TAG, this.sendReadMidStop, " ws.on message " + value);
        let jsonData = JSON.parse(value)
        this.parseResult(jsonData)
        if (this.sendReadMidStop == 1) {
          this.sendReadMidStop = 2
        }
      });
      this.ws.on("error", (str) => {
        console.info(TAG, this.sendReadMidStop,
          "ws error code" + str.code + "|data " + str.data + "| type" + typeof str + "| keys" +
          Object.keys(str));
      });
      this.ws.on("close", (code, reason) => {
        console.info(TAG, this.sendReadMidStop, "success close . code " + code + " reason " + JSON.stringify(reason));
        if (this.autoRestart && this.sendReadMidStop == 0) {
          this.recordStart()
        }
      });
      let err = await this.ws.connect(url)
      if (err) {
        console.log(TAG, this.sendReadMidStop, "websocket connect success")
      } else {
        console.log(TAG, this.sendReadMidStop, "websocket connect fail", JSON.stringify(err))
      }
      return
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  getWebSocketUrl() {
    return this.mainUrl
  }

  async sendStartFrame() {
    let TAG = "_:_sendStartFrame"
    try {
      let audioDataSend = this.audioData.splice(0, this.bufSize)
      let params = {
        common: {
          app_id: APPID,
        },
        business: {
          language: 'zh_cn',
          domain: 'iat',
          accent: 'mandarin',
          vad_eos: 10000,
        },
        data: {
          status: 0,
          format: 'audio/L16;rate=16000',
          encoding: 'raw',
          audio: urlUtil.toBase64(audioDataSend)
        },
      }
      console.log(TAG, this.sendReadMidStop, "sending startparams[", (this.cntSend++), "]", "audioData",
        this.audioData.length + this.bufSize, "->", this.audioData.length, JSON.stringify(params))
      return await this.ws.send(JSON.stringify(params))
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async sendMidFrame() {
    let TAG = "_:_sendMidFrame"
    try {
      let audioDataSend = this.audioData.splice(0, this.bufSize)
      let midParams = {
        data: {
          status: 1,
          format: 'audio/L16;rate=16000',
          encoding: 'raw',
          audio: urlUtil.toBase64(audioDataSend),
        },
      }
      console.log(TAG, this.sendReadMidStop, "sending midparams[", (this.cntSend++), "]", "audioData",
        this.audioData.length + this.bufSize, "->", this.audioData.length, JSON.stringify(midParams))
      return await this.ws.send(JSON.stringify(midParams));
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  async sendEndFrame() {
    let TAG = "_:_sendEndFrame"
    try {
      let endParams = {
        data: {
          status: 2,
          format: 'audio/L16;rate=16000',
          encoding: 'raw',
          audio: "",
        },
      }
      console.log(TAG, this.sendReadMidStop, "sending endparams[", (this.cntSend++), "]", "audioData",
        this.audioData.length,
        JSON.stringify(endParams))
      return await this.ws.send(JSON.stringify(endParams))
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }

  immediateStop() {
    this.ws.close(() => {
      console.log("_:_VR WS force stoped")
    })
  }

  parseResult(jsonData) {
    let TAG = "_:_parseResult"
    try {
      if (JSON.stringify(jsonData).includes("error_msg")) {
        promptAction.showToast({
          "message": JSON.stringify(jsonData), "duration": 5000
        })
      }
      console.log(TAG, this.sendReadMidStop, "result json" + JSON.stringify(jsonData))
      if (jsonData.data && jsonData.data.result) {
        let data = jsonData.data.result
        let str = ''
        let ws = data.ws
        for (let i = 0; i < ws.length; i++) {
          str = str + ws[i].cw[0].w
        }
        this.displayStr += str;
        console.log(TAG, this.sendReadMidStop, "result", str)
        let indexParams = getP() //MODIFIED 12_5 TO getP
        indexParams.voiceText += str
        setP(indexParams)
      }
      console.log("lsm jsonData.code---" + jsonData.code)
      console.log("lsm jsonData.data.status---" + jsonData.data.status)
      if (jsonData.code === 0 && jsonData.data.status === 2) {
        this.ws.close((err) => {
        });
      }
      if (jsonData.code !== 0) {
        this.ws.close((err) => {
          console.log('_:_ wsclose-- 222' + err);
        });
        console.log(`${jsonData.code}:${jsonData.message}`)
      }
    } catch (e) {
      console.error(TAG, JSON.stringify(e))
    }
  }
}
